#include "StdAfx.h"
#include "ILibavResample.h"
#include "MediaFrame.h"


extern "C"
{
#include "avcodec.h"
#include "avformat.h"
};



#define DECLARE_ALIGNED_8(t,v) __declspec(align(8)) t v
#define PHASE_BITS 4
#define NB_PHASES  (1 << PHASE_BITS)
#define NB_TAPS    4
#define FCENTER    1  /* index of the center of the filter */

struct ImgReSampleContext {
	int iwidth, iheight, owidth, oheight;
	int topBand, bottomBand, leftBand, rightBand;
	int padtop, padbottom, padleft, padright;
	int pad_owidth, pad_oheight;
	int h_incr, v_incr;
	DECLARE_ALIGNED_8(int16_t, h_filters[NB_PHASES][NB_TAPS]); /* horizontal filters */
	DECLARE_ALIGNED_8(int16_t, v_filters[NB_PHASES][NB_TAPS]); /* vertical filters */
	uint8_t *line_buf;
};

class CLibavImgResample : public ILibavImgResample
{
public:
	CLibavImgResample();
	virtual ~CLibavImgResample();

	BOOL Init(int srcW, int srcH, int dstW, int dstH);
	BOOL Process(CVideoFrame* pSrc, CVideoFrame** pDes);


private:
	BOOL close();

private:
	ImgReSampleContext* m_pImgReCxt;
	CVideoFrame*   m_pReTmpFrame;
	

};


CLibavImgResample::CLibavImgResample() : m_pImgReCxt(NULL), m_pReTmpFrame(NULL)
{

}

CLibavImgResample::~CLibavImgResample()
{

}

BOOL CLibavImgResample::Init(int srcW, int srcH, int dstW, int dstH)
{
	close();
	m_pImgReCxt = img_resample_init(dstW, dstH, srcW, srcH);
	if(!m_pImgReCxt) return FALSE;
	m_pReTmpFrame = new CVideoFrame;
	if(!m_pReTmpFrame) return FALSE;
	if(!m_pReTmpFrame->SetFormat(PIX_FMT_YUV420P, dstW, dstH))
		return FALSE;
	return TRUE;
	

}

BOOL CLibavImgResample::Process(CVideoFrame* pSrc, CVideoFrame** pDes)
{
	if(!pDes) return FALSE;
	AVPicture* pSrcPic = (AVPicture*)pSrc->GetAVFrame();
	AVPicture* pDesPic = (AVPicture*)m_pReTmpFrame->GetAVFrame();
	img_resample(m_pImgReCxt, (AVPicture*)m_pReTmpFrame->GetAVFrame(), pSrcPic);
	*pDes = m_pReTmpFrame;
	return TRUE;
}

BOOL CLibavImgResample::close()
{
	if(m_pImgReCxt){
		img_resample_close(m_pImgReCxt);
		m_pImgReCxt = NULL;
	}
	if(m_pReTmpFrame){
		delete m_pReTmpFrame;
		m_pReTmpFrame = NULL;
	}
	
	return TRUE;
}


//////////////////////////////////////////////////////////////


#define FELEM int16_t
typedef struct AVResampleContext{
	FELEM *filter_bank;
	int filter_length;
	int ideal_dst_incr;
	int dst_incr;
	int index;
	int frac;
	int src_incr;
	int compensation_distance;
	int phase_shift;
	int phase_mask;
	int linear;
}AVResampleContext;


struct ReSampleContext {
	struct AVResampleContext *resample_context;
	short *temp[2];
	int temp_len;
	float ratio;
	/* channel convert */
	int input_channels, output_channels, filter_channels;
};




class CLibavAuResample : public ILibavAuResample
{
public:
	CLibavAuResample();
	virtual ~CLibavAuResample();

	BOOL Init(int dstCh, int dstSampleRate, int srcCh, int srcSampleRate);
	BOOL Process(CAudioFrame* pSrc, CAudioFrame** pDst, int sampleCount);

private:
	void close();



private:
	ReSampleContext* m_pAuReCtx;
	CAudioFrame*     m_pAuTmpFrame;

};


CLibavAuResample::CLibavAuResample()
	:	m_pAuReCtx(NULL)
	,	m_pAuTmpFrame(NULL)
{

}

CLibavAuResample::~CLibavAuResample()
{
	close();
}

void CLibavAuResample::close()
{
	if(m_pAuReCtx){
		audio_resample_close(m_pAuReCtx);
		m_pAuReCtx = NULL;
	}
	if(m_pAuTmpFrame){
		delete m_pAuTmpFrame;
		m_pAuTmpFrame = NULL;
	}
}

BOOL CLibavAuResample::Init(int dstCh, int dstSampleRate, int srcCh, int srcSampleRate)
{
	close();
	m_pAuReCtx = audio_resample_init(dstCh, srcCh, dstSampleRate, srcSampleRate);
	if(!m_pAuReCtx) return FALSE;
	m_pAuTmpFrame = new CAudioFrame;
	if(!m_pAuTmpFrame) return FALSE;
	m_pAuTmpFrame->InitDefaultBuffer();
	m_pAuTmpFrame->SetFormat(dstCh, dstSampleRate);
	return TRUE;	
}

BOOL CLibavAuResample::Process(CAudioFrame *pSrc, CAudioFrame **pDst, int sampleCount)
{
	if(!pDst) return FALSE;
	int sc = audio_resample(m_pAuReCtx, m_pAuTmpFrame->GetDataPointer(), pSrc->GetDataPointer(), sampleCount);
	m_pAuTmpFrame->SetSampleCount(sc);
	*pDst = m_pAuTmpFrame;
	return TRUE;
}


ILibavAuResample* CreateLibAuResample()
{
	return (ILibavAuResample*) new CLibavAuResample;
}

ILibavImgResample* CreateLibImgResample()
{
	return (ILibavImgResample*) new CLibavImgResample;
}
















//ILibavResample* CreateLibavResample()
//{
//	return new CLibavImgResample;
//}
//
